#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "algorithm_by_RF.h"
#include "max30102.h"
#include <SPI.h>
#include <string.h>
#include "max30102.h"

#include <ESP8266_Seniverse.h>
#include "spo2_algorithm.h"


#include <NTPClient.h>
#include <WiFiManager.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include "weather_icons.h"


// put function declarations here:
WiFiUDP ntpUDP;
WiFiClient client;
NTPClient timeClient(ntpUDP,"pool.ntp.org", 8*3600, 60000);

Adafruit_SSD1306 oled(128, 64, &Wire,-1);
int bee = 13;
bool auto_clock = 0;//默认关闭
int button_pin =2;
int hour_pin=D3;
int minute_pin=D8;
int keynum;
int clock_hour=11;
int clock_minute=26;
float n_spo2, ratio, correl; // SPO2 value
int8_t ch_spo2_valid;        // indicator to show if the SPO2 calculation is valid
int32_t n_heartrate;         // heart rate value
int8_t ch_hr_valid;          // indicator to show if the heart rate calculation is valid
int32_t i;

const char* host = "43.139.43.195";
const int port = 9002;//demo1 tcp 使用 9002端口

const char* id = "Cap";
int tick = 1000;

U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/5, /* data=*/4, /* reset=*/U8X8_PIN_NONE); // 软件 I2C

const byte oxiInt = 16; // pin connected to MAX30102 INT
char hours[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};



// 定义分钟数组
char minutes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59};


int b1_state=0,b1_state_last=0;
int abc=0;
uint32_t elapsedTime, timeStart;
int a1;
int32_t last_hr = 40;       // 上一次的心率数据
float last_spo2 = 40;     // 上一次的血氧数据
uint32_t aun_ir, aun_red;
uint32_t aun_ir_buffer[BUFFER_SIZE];  // infrared LED sensor data
uint32_t aun_red_buffer[BUFFER_SIZE]; // red LED sensor data
float old_n_spo2;                     // Previous SPO2 value
uint8_t uch_dummy;
bool showMeasuring = false;
int weekDay;
bool status = false;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

const char *ssid     = "nihao"; //账号
const char *password = "QweasDCAP";//密码
int OnTime = 0; //显示变量
String reqUserKey = "SfuTur3ZnmsFWLDg5";// 私钥
String reqLocation = "guangzhou";// 城市
String reqUnit = "c";// 摄氏/华氏
typedef struct
{
  int zuigaowendu;
  int zuidiwendu;
  int shidu;
  int tianqitubiao;
}tianqixinxi; //最高温最低温和湿度和天气现象代码的结构体
tianqixinxi day1,day2,day3;



WeatherNow weatherNow;
Forecast forecast;
int progress=0;
int mode=1;






void OLED_ShowString(uint8_t x, uint8_t y, uint8_t font_size, String string);  
void OLED_ShowNum(uint8_t x, uint8_t y, uint8_t font_size, int Num);
void OLED_Init();
void print_hr_spo2(int val_hr, int val_spo2,int old_heart,int old_spo2);
void print_measuring(int n);
void print_press();
void DisplayTianqi();
void DisplayTime();
void Get_weather();
void connectWiFi();
void lcd_show();
void mode0();//显示时间
void mode1();//血氧心率检测
void mode2();//天气预报
void u8g2begin();
int key_scan();
void setup() {
  







  pinMode(button_pin, INPUT_PULLUP);
  pinMode(hour_pin, INPUT_PULLUP);
 
	pinMode(bee, OUTPUT);
	digitalWrite(bee,HIGH);
	
  // put your setup code here, to run once:
  Serial.begin(115200);  // initialize serial communication at 115200 bits per second:
  Wire.begin(4, 5); 
  Serial.println("Initializing");
  maxim_max30102_reset(); // resets the MAX30102
  maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_dummy); // Reads/clears the interrupt status register
  maxim_max30102_init();                                  // initialize the MAX30102
  old_n_spo2 = 0.0;
  Serial.println(F("Time[s]\tSpO2\tHR\tRatio\tCorr"));
  timeStart = millis();
  pinMode(oxiInt, INPUT);
 
 // u8g2.setI2CAddress(0x3C);
 // u8g2.setBusClock(800000);
  u8g2begin();
  /////////////////////////////////////////////////////////////
  OLED_Init();
  oled.clearDisplay();
  OLED_ShowString(1, 1, 2, "Connecting..."); 
  oled.display();

	
  
  connectWiFi();
  //WiFiManager wifiManager;
  //wifiManager.autoConnect("ESP8266");
  client.connect(host,port);

  

  oled.clearDisplay();
  weatherNow.config(reqUserKey, reqLocation, reqUnit);
  forecast.config(reqUserKey, reqLocation, reqUnit);
  timeClient.begin();
  client.setTimeout(100);
  OLED_ShowString(1, 10, 1, "Connected to");
  OLED_ShowString(1, 20, 1, WiFi.SSID());

  OLED_ShowString(1, 30, 1, "IP:");
  oled.setTextSize(1);
  oled.setCursor(20, 30);
  oled.println(WiFi.localIP());  
  weekDay = timeClient.getDay();
  oled.display();
  delay ( 100 );
  Serial.println(WiFi.localIP());
  oled.clearDisplay();
  
}


void loop()
{	//更新时间



while(1){
  if (client.connect(host,port))
  {
    Serial.println("host connected!");
    //发送第一条TCP数据，发送ID号
    client.print(id);
  }
  else
  {
    // TCP连接异常
    Serial.println("host connecting...");
    delay(500);
  }
  while (client.connected()) {


  keynum=key_scan();
  if (keynum==1){
  mode++;
  } else if (keynum==2){
  clock_hour++;

  }
  lcd_show();

  }


}

  
}
void display_tq(int dday,int tq,int dw,int gw,int sd)
{
    switch(dday)  //显示今明后天
    {
        case 0:u8g2.setCursor(85, 15);  //设置光标位置
               u8g2.print("今天");
        break;  
        case 1:u8g2.setCursor(85, 15);
               u8g2.print("明天");
        break;
        case 2:u8g2.setCursor(85, 15);
               u8g2.print("后天");
        break;
    }    
	
    switch(tq)  //显示天气图片
    {
      case 0:u8g2.drawXBMP( 0 , 0 , 48 , 48, qintian );
            break;
      case 4:u8g2.drawXBMP( 0 , 0 , 48 , 48, duoyun );
            break;
      case 9:u8g2.drawXBMP( 0 , 0 , 48 , 48, yintian );
            break;
      case 13:u8g2.drawXBMP( 0 , 0 , 48 , 48, xiaoyu );
            break;
      case 14:u8g2.drawXBMP( 0 , 0 , 48 , 48, zhongyu );
            break;
      case 15:u8g2.drawXBMP( 0 , 0 , 48 , 48, dayu );
            break;
     }
			
     u8g2.setCursor(90,30);
     String str3 = weathers[tq];  //显示天气(中文)
     u8g2.print(str3);
     u8g2.setCursor(70, 45);
     String str1 = test[0] + dw + "-" + gw + "℃"; //显示最低温度到最高温度
     u8g2.print(str1);
     u8g2.setCursor(70, 60);
     u8g2.print("湿度:");
     u8g2.setCursor(100, 60);
     String str2 = test[1] + sd + "%";  //显示湿度
     u8g2.print(str2);
}  
void DisplayZZXS(int dday)
{
    switch(dday)
    {
        case 0:display_tq(dday,day1.tianqitubiao,day1.zuidiwendu,day1.zuigaowendu,day1.shidu);
        break;  
        case 1:display_tq(dday,day2.tianqitubiao,day2.zuidiwendu,day2.zuigaowendu,day2.shidu);
        break;  
        case 2:display_tq(dday,day3.tianqitubiao,day3.zuidiwendu,day3.zuigaowendu,day3.shidu);
        break;  
    }
}

void DisplayTianqi()
{
   if(OnTime > 1)
    {
        DisplayZZXS(OnTime-2);
        //Serial.println("打印天气中");  
    }
}

void Get_weather()
{
  if (millis()> 5000 && forecast.update()) { // 每五秒获取一次天气数据
  {
    day1.tianqitubiao = forecast.getDayCode(0);
    day1.zuigaowendu = forecast.getHigh(0);
    day1.zuidiwendu = forecast.getLow(0);
    day1.shidu =  forecast.getHumidity(0);
    day2.tianqitubiao = forecast.getDayCode(1);
    day2.zuigaowendu = forecast.getHigh(1);
    day2.zuidiwendu = forecast.getLow(1);
    day2.shidu =  forecast.getHumidity(1);
    day3.tianqitubiao = forecast.getDayCode(2);
    day3.zuigaowendu = forecast.getHigh(2);
    day3.zuidiwendu = forecast.getLow(2);
    day3.shidu =  forecast.getHumidity(2);
  
    OnTime++;   //显示标志位 0,1,2显示时间 3显示今天天气 4显示明天天气 5显示后天天气
    OnTime%=5;    
  }
 }
}

void DisplayTime()
{
  timeClient.update();
  String time = timeClient.getFormattedTime().substring(0, 5);
  u8g2.setFont(u8g2_font_wqy16_t_gb2312);
  if(OnTime ==0 or OnTime == 1)
  {
    u8g2.setCursor(55, 30);
    u8g2.print("广州");
   
  
     
     
    
  }
}

void connectWiFi() {
	// 建立WiFiManager对象
	
	WiFiManager wifiManager;
	// 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
	wifiManager.autoConnect("ESP8266");

   //等待WIFI连接成功
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi connecting...");
    delay(500);
  }
  }
  void print_press(){
	u8g2.clearBuffer();
   
	
	
  
	
	/*
	  u8g2.setFont(u8g2_font_ncenB12_tr); 
	u8g2.setCursor(0,14);
	u8g2.print(" HR");
	u8g2.setCursor(60,14);
	u8g2.print("SPO2");
	u8g2.drawXBMP(0,20,32,32,epd_bitmap_allArray[0]);  
  
  
	u8g2.drawXBMP(60,20,32,32,epd_bitmap_allArray1[0]);
	u8g2.setFont(u8g2_font_fur20_tr);
	u8g2.drawStr(10, 38, "---");
	
	
	u8g2.setFont(u8g2_font_fur30_tr); 
	u8g2.drawStr(65, 48, "---");
  */
	u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
	u8g2.setCursor(10,63);
	u8g2.print(" 无接触,请准确佩戴");    
	u8g2.setCursor(10,35);
	u8g2.print(" 测量结果仅供参考");    
	u8g2.setCursor(10,49);
	u8g2.print(" 并非医疗诊断依据");    
	u8g2.sendBuffer();    
  }
  void print_measuring(int n){
	u8g2.clearBuffer();
	/*
	u8g2.setFont(u8g2_font_fub14_tr); 
   
	u8g2.setCursor(0,14);
	u8g2.print(" HR");
	u8g2.setCursor(60,14);
	u8g2.print("SPO2");
  const char * str2 = timeClient.getFormattedTime().c_str();
   u8g2.drawStr(1, 0,str2);
  */
   // u8g2.drawXBMP(60,20,32,32,heratbeatallArray[0]); 
  
   u8g2.setFont(u8g2_font_ncenB12_tr); 
   switch (n)
   {
   case 0:
   u8g2.setCursor(0,5);
	 u8g2.print("----");

	   break;
   case 1:
   u8g2.setCursor(0,5);
   u8g2.print("--------"); 

	   break;
   case 2:
   u8g2.setCursor(0,5);
   u8g2.print("-------------"); 
 
	   break;
   case 3:
   u8g2.setCursor(0,5);
   u8g2.print("------------------"); 
 
	   break;
   case 4:
   u8g2.setCursor(0,5);
   u8g2.print("-------------------------"); 
 
	   break;	
   case 5:
   u8g2.setCursor(0,5);
   u8g2.print("--------------------------------"); 
 
	   break;
   case 6:
   u8g2.setCursor(0,5);
	   u8g2.print("                                               "); 
	   
		   break;
   default:
	   break;
   }
    u8g2.drawXBMP(0,20,32,32,epd_bitmap_allArray[0]);  
	u8g2.drawXBMP(60,20,32,32,epd_bitmap_allArray1[0]);
	u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
	u8g2.setCursor(20,62);
	u8g2.print("测量中,请保持静止");    
	u8g2.sendBuffer(); 
  }
  void print_hr_spo2(int val_hr, int val_spo2,int old_heart,int old_spo2){
	if(val_hr > 999 || val_hr < 0){
	  return;
	}
	if(val_spo2 > 100 || val_spo2 < 0){
	  return;
	}
  
	u8g2.clearBuffer();
	u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
	u8g2.setCursor(0, 27);
	u8g2.print("新：");
	
	u8g2.setCursor(0, 47);
	u8g2.print("旧：");
	u8g2.setFont(u8g2_font_ncenB12_tr); 
	
  
  
  
	u8g2.setCursor(0,14);
	u8g2.print(" HR");
	u8g2.setCursor(60,14);
	u8g2.print("SPO2");
	
	char str_hr[4];  //新心率
	u8g2.setFont(u8g2_font_ncenB12_tr);
	itoa(val_hr, str_hr, 10);
	if(val_hr > 99){
	  u8g2.drawStr(3, 35, str_hr);
	}else if(val_hr > 9){
	  u8g2.drawStr(10,35, str_hr);
	}else{
	  u8g2.drawStr(15,35, str_hr);
	}
	//
	char str_spo2[4];//新血氧
	u8g2.setFont(u8g2_font_ncenB12_tr); 
	itoa(val_spo2, str_spo2, 10);  
	if(val_spo2 > 99){
	  u8g2.drawStr(70, 35, str_spo2);
	}else if(val_spo2 > 9){
	  u8g2.drawStr(75, 35, str_spo2);
	}else{
	  u8g2.drawStr(80, 35, str_spo2);    
	}
	u8g2.setCursor(35,35);
	u8g2.print("bpm");
	u8g2.setCursor(105,35);
	u8g2.print("%");
	//
	if (last_hr<150&&last_hr>50){
	  char str_hr1[4];  //旧心率
	  u8g2.setFont(u8g2_font_ncenB12_tr);
	  itoa(old_heart, str_hr1, 10);
	  if(old_heart > 99){
		u8g2.drawStr(3, 55, str_hr1);
	  }else if(old_heart > 9){
		u8g2.drawStr(10,55, str_hr1);
	  }else{
		u8g2.drawStr(15,55, str_hr1);
	  }
	  
	//
	
		char str_spo21[4];//旧血氧
		u8g2.setFont(u8g2_font_ncenB12_tr); 
		itoa(old_spo2, str_spo21, 10);  
		if(old_spo2 > 99){
		  u8g2.drawStr(70, 55, str_spo21);
		}else if(old_spo2 > 9){
		  u8g2.drawStr(75, 55, str_spo21);
		}else{
		  u8g2.drawStr(80, 55, str_spo21);    
		}
		u8g2.setFont(u8g2_font_ncenB12_tr); 
  
  
	}
	  u8g2.setCursor(35,55);
	  u8g2.print("bpm");
	  u8g2.setCursor(105,55);
	  u8g2.print("%");
	  u8g2.sendBuffer();   
  
  
  
  }
  void OLED_Init()
{
  oled.begin(SSD1306_SWITCHCAPVCC,0x3C);
  oled.setTextColor(WHITE);//开像素点发光
  oled.clearDisplay();//清屏
  
}
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t font_size, String string)
{
  oled.setTextSize(font_size);
  oled.setCursor(x, y);
  oled.println(string);  
  
}
void OLED_ShowNum(uint8_t x, uint8_t y, uint8_t font_size, int Num)
{
  oled.setTextSize(font_size);
  oled.setCursor(x, y);
  oled.println(Num); 
  
}
void mode0(){  //x显示日期时间
if (clock_hour>24){

  clock_hour=0;
}
if (clock_minute>59){

  clock_minute=0;
}
	String nowtime = timeClient.getFormattedTime();
	String hour =  nowtime.substring(0, 2);
	String minute = nowtime.substring(3, 5);

	int currentHour = hour.toInt(); // 将 hour 转换为 int
  int currentMinute = minute.toInt(); // 将 minute 转换为 int
  if (currentHour == clock_hour and currentMinute == clock_minute ) {
    auto_clock = true;
  }
  else {
    auto_clock = false;
  }
  if ( auto_clock == true)
  {
    Serial.println("自动闹铃");
    digitalWrite(bee,LOW);
  }
  else   {
	digitalWrite(bee,HIGH);
    
  }
	time_t t;
	char s[100];
    struct tm *p;
	t=timeClient.getEpochTime();
	p=gmtime(&t);
    //strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", p);
    strftime(s, sizeof(s), "%Y %m %d ", p);
	timeClient.update();
  
	 OLED_ShowString(0, 0,2, s);
 
   
   OLED_ShowString(0, 20, 1, "CLOCK ON ");
   OLED_ShowNum(50, 20, 1, clock_hour);
	 OLED_ShowString(60, 20, 1, ":");
	 OLED_ShowNum(68, 20, 1, clock_minute);
	 
 

	 OLED_ShowString(0, 30, 2, daysOfTheWeek[timeClient.getDay()]);
	 OLED_ShowString(0, 50, 2, timeClient.getFormattedTime());
	 oled.display();
	 oled.clearDisplay();
	
}
unsigned long lastHeartbeatTime = 0;  // 用于存储上一次发送心跳数据的时间
const long heartbeatInterval = 5000;  // 心跳间隔时间，单位为毫秒（5秒）
void mode1(){    //测血氧心率

// Serial.println("looping");


// buffer length of BUFFER_SIZE stores ST seconds of samples running at FS sps
// read BUFFER_SIZE samples, and determine the signal range
for (i = 0; i < BUFFER_SIZE; i++)
{

  
  
  while (digitalRead(oxiInt) == 1);
	// wait until the interrupt pin asserts
  delay(1);
  // wdt_reset();
#ifdef REVERSE_LED
  maxim_max30102_read_fifo(&aun_ir, &aun_red); // read from MAX30102 FIFO
#else
  maxim_max30102_read_fifo(&aun_red, &aun_ir); // read from MAX30102 FIFO
#endif
  if (aun_ir < 5000)
  {
	break;	
  }
  if (i >10&&i<90&&ch_spo2_valid!=1)
  {
	
	
	
	if(showMeasuring){
	   print_measuring(i%6);
	  
	}
	Serial.print("Measuring...");
  }
  *(aun_ir_buffer + i) = aun_ir;
  *(aun_red_buffer + i) = aun_red;
  // 计算进度百分比
  
 
	
}

if (aun_ir < 5000)
{
 
  a1=0;
  print_press();
  showMeasuring = true;
  Serial.print("Put On Finger");
}
else
{
 
 
  // calculate heart rate and SpO2 after BUFFER_SIZE samples (ST seconds of samples) using Robert's method
  rf_heart_rate_and_oxygen_saturation(aun_ir_buffer, BUFFER_SIZE, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heartrate, &ch_hr_valid, &ratio, &correl);
  // Serial.println("rf_heart_rate_and_oxygen_saturation");
  elapsedTime = millis() - timeStart;
  elapsedTime /= 1000; // Time in seconds

  if (ch_hr_valid && ch_spo2_valid)
  {
	showMeasuring = false;

	a1=1;
  


	print_hr_spo2(n_heartrate, (int)(n_spo2+0.5),last_hr,(int)last_spo2);
  if(client.connected()&&n_heartrate>40) {
                    
 
    //client.print(tick);
    client.print("X");
    client.print(n_heartrate);
    client.print("|Y");
    client.print((int)(n_spo2+0.5));
    tick++;
    delay(200);
    } 


	last_hr = n_heartrate;

	last_spo2 = (n_spo2 + 0.5);

	old_n_spo2 = n_spo2;
  } if (ch_hr_valid ==0 || ch_spo2_valid==0)
  {
	showMeasuring = false;

	a1=1;
	print_hr_spo2(n_heartrate, (int)(n_spo2+0.5),last_hr,(int)last_spo2);
  if(client.connected()&&n_heartrate>40) {
                    

    //client.print(tick);
    client.print("X");
    client.print(n_heartrate);
    client.print("|Y");
    client.print((int)(n_spo2+0.5));
    tick++;
    delay(200);
    }






	old_n_spo2 = n_spo2;
  }/*else if (a1!=1) { // 如果计算无效，提示用户重新测量

	u8g2.clearBuffer();
	print_measuring();
	showMeasuring = false;
	u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
	u8g2.setCursor(10, 30);
	u8g2.print("测量失败，请重新测量");
	u8g2.sendBuffer();

	

	
  }*/
}

}
unsigned long previousMillis = 0;  // 用于存储上一次翻页的时间
const long interval = 2000;        // 翻页间隔时间，单位为毫秒

void mode2() {  //显示天气
    unsigned long currentMillis = millis();  // 获取当前时间
     
    // 检查是否到达翻页时间
    if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;  // 更新上一次翻页的时间
       
        // 清空缓冲区并显示新内容
        u8g2.clearBuffer();
        u8g2.setFont(u8g2_font_wqy12_t_gb2312);
        DisplayTianqi();  // 显示天气
        DisplayTime();    // 显示时间
        Get_weather();    // 获取天气数据
        u8g2.sendBuffer();// 显示缓冲区内容
    }
}
void u8g2begin(){

	u8g2.enableUTF8Print(); //中文必要设置
	u8g2.setFontMode(1);   
	u8g2.setBusClock(800000); 
	u8g2.begin();
	u8g2.setContrast(150);
	u8g2.clearBuffer();
	u8g2.setFont(u8g2_font_ncenB12_tr);

}
int key_scan() {
int keynum=0;
if (digitalRead(button_pin)==0){
  delay(30);
  while (digitalRead(button_pin)==0);
  delay(30);
  keynum=1;
}else if (digitalRead(hour_pin)==0){
  delay(30);
  while (digitalRead(hour_pin)==0);
  delay(30);
  keynum=2;
}


return keynum;
  
}

void lcd_show() {
  switch (mode%3) {
      case 0:

          mode0();  // 显示时间
          break;
      case 1:  
   
          mode1();
          break;
      case 2:
          mode2();  // 天气预报
          break;

  }
}